package com.gcloud.mesh.dcs.aop;

import java.lang.reflect.Method;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.stereotype.Component;

import com.gcloud.mesh.dcs.annotation.SchedulerLog;
import com.gcloud.mesh.dcs.dao.SchedulerStepDao;
import com.gcloud.mesh.dcs.entity.SchedulerStepEntity;
import com.gcloud.mesh.dcs.enums.SchedulerStepStatus;
import com.gcloud.mesh.header.exception.BaseException;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Aspect
@Component
public class SchedulerJobStepAop {

	@Autowired
	private SchedulerStepDao schedulerStepDao;
	
	private SecureRandom rd = new SecureRandom();

	@Around("@annotation(com.gcloud.mesh.dcs.annotation.SchedulerLog)")
	public Object around(ProceedingJoinPoint joinPoint) {
		String stepId = UUID.randomUUID().toString();

		try {

			Class<?> targetCls = joinPoint.getTarget().getClass();
			MethodSignature ms = (MethodSignature) joinPoint.getSignature();
			Method method = targetCls.getDeclaredMethod(ms.getName(), ms.getParameterTypes());
			SchedulerLog requiredLog = method.getAnnotation(SchedulerLog.class);
			if (requiredLog != null) {
				SchedulerStepEntity sse = new SchedulerStepEntity();
				sse.setBeginTime(new Date());
				sse.setId(stepId);
				sse.setName(requiredLog.stepName());

				Map<String, Object> argMap = getFieldsName(joinPoint);
				Object jobId = argMap.get("jobId");
				if (jobId != null) {
					sse.setSchedulerJobId(String.valueOf(jobId));
				}
				sse.setStatus(SchedulerStepStatus.PROGRESS.getValue());
				schedulerStepDao.save(sse);
			}

			// TODO 随机睡眠时间
//			Random rd = new Random();
//			Thread.sleep(1000 * rd.nextInt(20));

			TimeUnit.SECONDS.sleep(1);

			Object res = joinPoint.proceed();

			updateStepStatus(stepId, SchedulerStepStatus.SUCCESS);

			return res;
		} catch (Throwable e) {
			log.error("[SchedulerJobStepAop]调度错误", e);

			updateStepStatus(stepId, SchedulerStepStatus.FAIL);
			throw new BaseException(e);
		} finally {
//			System.out.println("around");
		}
	}

	private void updateStepStatus(String stepId, SchedulerStepStatus status) {
		SchedulerStepEntity schedulerStep = schedulerStepDao.getById(stepId);
		if (schedulerStep != null) {

			List<String> fields = new ArrayList<>();
			fields.add("status");
			schedulerStep.setStatus(status.getValue());

			fields.add("endTime");
			schedulerStep.setEndTime(new Date());

			schedulerStepDao.update(schedulerStep, fields);
		}
	}

	/**
	 * 获取参数列表
	 *
	 * @param joinPoint
	 * @return
	 * @throws ClassNotFoundException
	 * @throws NoSuchMethodException
	 */
	private static Map<String, Object> getFieldsName(ProceedingJoinPoint joinPoint) {
		// 参数值
		Object[] args = joinPoint.getArgs();
		ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer();
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		Method method = signature.getMethod();
		String[] parameterNames = pnd.getParameterNames(method);
		Map<String, Object> paramMap = new HashMap<>();
		for (int i = 0; i < parameterNames.length; i++) {
			paramMap.put(parameterNames[i], args[i]);
		}
		return paramMap;
	}

}
